package com.seadragon.app.dms.controller;

import static com.seadragon.app.dms.model.DmsConstants.CUSTOMER_STATUS_ACTIVE;

import java.beans.PropertyEditorSupport;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.validation.Valid;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.mail.EmailException;
import org.apache.commons.mail.HtmlEmail;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.support.SessionStatus;

import com.seadragon.app.dms.model.CreditCard;
import com.seadragon.app.dms.model.Customer;
import com.seadragon.app.dms.model.DmsConstants;
import com.seadragon.app.dms.service.CustomerService;

@Controller
public class LoginController {
	private Logger logger = LoggerFactory.getLogger(LoginController.class);
	@Autowired
	private CustomerService customerService;
	
	private MessageDigest md;
	
	public LoginController(){
		try{
			md = MessageDigest.getInstance("SHA-256");
		}catch(NoSuchAlgorithmException ex){
			logger.error("Failed to create MessageDigest", ex);
		}
	}
	@InitBinder
	protected void initBinder(WebDataBinder binder){
		SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy");
//		sdf.setLenient(false);
//		binder.registerCustomEditor(Date.class, new CustomDateEditor(sdf, true));
		binder.registerCustomEditor(Date.class, new PropertyEditorSupport() {
		    public void setAsText(String value) {
		        try {
		            setValue(new SimpleDateFormat("MM/dd/yyyy").parse(value));
		        } catch(ParseException e) {
		            setValue(null);
		        }
		    }

		    public String getAsText() {
		        return new SimpleDateFormat("MM/dd/yyyy").format((Date) getValue());
		    }        

		});
//		binder.setValidator(new CustomerValidator());
	}
	
	//check the availability of the username
	@RequestMapping(value="/check-username.json", method=RequestMethod.GET)
	public @ResponseBody boolean checkUsername(HttpServletRequest request,HttpSession session, @RequestParam  String userName) {
		Customer customer = null;
		try {
			customer = customerService.findByUserName(userName);
			
		} catch (Exception e) {
			logger.error("Failed to get customer for username= " + userName, e);
		}
		Customer currentUser = (Customer)session.getAttribute(DmsConstants.SESSION_SCOPED_USER);
		//for user profile update, username can be the one of herself
		return customer==null||(currentUser!=null&&userName.equals(currentUser.getUserName()));
	}
	
	@RequestMapping(value="/forgot-password.html", method=RequestMethod.POST)
	public String forgotPassword(HttpServletRequest request,HttpSession session,@RequestParam String userName, Model model) {
		/*todo:
		 * 1.check if email exist
		 * 2. if exists , send email for a url where user can reset password
		 * 3. if email doesn't exist, ignore silently.
		 */
		Customer customer = customerService.resetPassword(userName);
		List<String> infoMsgs = new ArrayList<String>();
		if(customer == null){
			infoMsgs.add("The email you inputed doesn't exist in our system, please try again later.");
		}else{
			infoMsgs.add("An email has been sent to "+ userName+" for password reset.");
			StringBuilder message = new StringBuilder();
			message.append("<html>");
			message.append("<head>");
			message.append("<title>Reset yoru password on dms.com</title>");
			message.append("</head>");
			message.append("<body>");
			message.append("<p>Please clilk following link to reset your password.</p>");
			message.append("<p><a href=\"http://localhost:8080/dms/resetPassword.html?id=");
			message.append(customer.getToken());
			message.append("\">");
			message.append("http://localhost:8080/dms/resetPassword.html/?id=");
			message.append(customer.getToken());
			message.append("</a></p>");
			message.append("</body>");
			message.append("</html>");
			sendEmail(customer.getUserName(), customer.getName(), "Reset your password on dms.com!", message.toString());			
		}
		model.addAttribute("infoMsgs", infoMsgs);
		model.addAttribute("selectedMenuItem", "reg-login");
		return "regAndLogin";
	}
	
	@RequestMapping(value="/Logout.html", method=RequestMethod.GET)
	public String doLogout(HttpServletRequest request,HttpSession session,Model model) {
		session.invalidate();
		return "regAndLogin";
	}
	
	@RequestMapping(value="/Login.html", method=RequestMethod.POST)
	public String doLogIn(HttpServletRequest request,HttpSession session, @RequestParam String userName, @RequestParam String password,Model model) {
		boolean loginSuccessful=true;
		Customer customer = customerService.findByUserName(userName);
		if(customer == null || !customer.getPassword().equalsIgnoreCase(encrypt(password)) || customer.getStatus() != CUSTOMER_STATUS_ACTIVE){
			loginSuccessful=false;
			List<String> errMsgs = new ArrayList<String>();
			errMsgs.add("User doesn't exist");
			errMsgs.add("Invalid username or passowrd");
			errMsgs.add("Your account isn't activated");
			model.addAttribute("errMsgs", errMsgs);
			model.addAttribute("selectedMenuItem", "reg-login");
		} else {
			session.setAttribute(DmsConstants.SESSION_SCOPED_USER, customer);
		}
		
		return (loginSuccessful)?"redirect:/index.html":"regAndLogin";
	}
	
	@RequestMapping(value="/Login.html", method=RequestMethod.GET)
	public String show() {
		return "welcome";
	}
	
	@RequestMapping(value = "/signup.html", method = RequestMethod.POST)
	public String login(@ModelAttribute("customer") @Valid Customer customer, BindingResult result, SessionStatus status,@RequestParam Date dateOfBirth, Model model) {
		logger.info("Username: " + customer.getUserName());
		logger.info("Password: " + customer.getPassword());
		customer.setDateOfBirth(dateOfBirth);
		customer.setPassword(encrypt(customer.getPassword()));

		model.addAttribute("selectedMenuItem", "reg-login");
		customer.setToken(UUID.randomUUID().toString());
		Set<CreditCard> creditCardList = new HashSet<CreditCard>();
		CreditCard cc = new CreditCard();
		cc.setType("AMEX");
		cc.setAccountNumber("41111");
		cc.setSecurityCode("123");
		cc.setNameAppearedOnCard("Yadong Zhu");
		cc.setExpirationDate(new GregorianCalendar(2015,6,25).getTime());
		creditCardList.add(cc);
		
		cc=new CreditCard();
		cc.setType("VISA");
		cc.setAccountNumber("52222");
		cc.setSecurityCode("456");
		cc.setNameAppearedOnCard("Yadong2");
		cc.setExpirationDate(new GregorianCalendar(2015,8,15).getTime());
		creditCardList.add(cc);
		
		cc=new CreditCard();
		cc.setType("MSTR");
		cc.setAccountNumber("7888");
		cc.setSecurityCode("987");
		cc.setNameAppearedOnCard("Yadong3");
		cc.setExpirationDate(new GregorianCalendar(2018,9,18).getTime());	
		creditCardList.add(cc);
		customer.setCreditCards(creditCardList);
		customerService.save(customer);
		StringBuilder message = new StringBuilder();
		message.append("<html>");
		message.append("<head>");
		message.append("<title>Activate your new account on dms.com</title>");
		message.append("</head>");
		message.append("<body>");
		message.append("<p>Please clilk following link to complete your signup process, thanks very much and welcome to dms.com</p>");
		message.append("<p><a href=\"http://localhost:8080/dms/activate.html?id=");
		message.append(customer.getToken());
		message.append("\">");
		message.append("http://localhost:8080/dms/activate.html?id=");
		message.append(customer.getToken());
		message.append("</a></p>");
		message.append("</body>");
		message.append("</html>");
		sendEmail(customer.getUserName(), customer.getName(), "Activate your new accout on dms.com!", message.toString());
		return "regAndLogin";
	}
	
	@RequestMapping(value = "/my-profile.html", method = RequestMethod.GET)
	public String showProfile(HttpServletRequest request,HttpSession session, Model model) {
//		if(session.getAttribute("user") != null){
//			model.addAttribute("user", session.getAttribute("user"));
//		}
		return "myProfile";
	}
	@RequestMapping(value = "/my-profile.html", method = RequestMethod.POST)
	public String updateProfile(@ModelAttribute("customer") @Valid Customer customer, BindingResult result, HttpServletRequest request,HttpSession session,@RequestParam Date dateOfBirth, Model model) {
		if(session.getAttribute(DmsConstants.SESSION_SCOPED_USER) != null){
			customer.setDateOfBirth(dateOfBirth);
			customerService.update(customer);
			//update session
			session.setAttribute(DmsConstants.SESSION_SCOPED_USER, customer);
		}
		return "myProfile";
	}
	@RequestMapping(value = "/reg-login.html", method = RequestMethod.GET)
	public String login(HttpServletRequest request,HttpSession session, Model model) {
		if(session.getAttribute(DmsConstants.SESSION_SCOPED_USER) == null){
			model.addAttribute("selectedMenuItem", "reg-login");
			return "regAndLogin";
		}else{
			return "home";
		}
	}
	
	@RequestMapping(value = "/activate.html", method = RequestMethod.GET)
	public String activate(HttpSession session, @RequestParam UUID id, Model model) {
		customerService.activate(id);
		return "home";
	}
	
	private String encrypt(String password){
		byte[] raw = md.digest(password.getBytes());
		return new String(Base64.encodeBase64(raw));
	}

	private void sendEmail(String emailTo, String nameTo, String subject, String message){
		HtmlEmail email = new HtmlEmail();
		email.setAuthentication("deliverymanagementsystem842@gmail.com", "Dms12345");
		email.setSmtpPort(465);
		email.setHostName("smtp.gmail.com");
		email.setSSLOnConnect(true);
		try{
			email.addTo(emailTo, nameTo);
			email.setFrom("wang.seadragon@gmail.com", "kidsserviceresources.com");
			email.setSubject(subject);
			email.setHtmlMsg(message);
			email.send();
		}catch(EmailException ex){
			logger.error("Failed to create an email to " + emailTo, ex);
		}
	}
}
